package fm.dao;

import fm.cache.SolrConfig;
import fm.exception.BizException;
import fm.util.DateUtils;
import fm.util.GeoUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.AnalysisParams;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by CM on 17/5/6.
 */
public class SolrBaseDao {
    private static Logger LOGGER = LoggerFactory.getLogger(SolrBaseDao.class);

    private static HttpSolrClient solr;

    public static final void init() {
        if (SolrConfig.getConfig("solr_url") == null) {
            throw new RuntimeException("没有配置SOLR相关信息，无法查询！");
        }
        try {
            String baseUrl = SolrConfig.getConfig("solr_url").toString();
            solr = new HttpSolrClient.Builder(baseUrl).build();
            solr.setConnectionTimeout(30000);
            solr.setDefaultMaxConnectionsPerHost(100);
            solr.setMaxTotalConnections(100);
        } catch (Exception e) {
            LOGGER.error("初始化SOLR链接发生错误", e);
        }
    }

    public static List<Map<String, Object>> queryFromeSolrByPage(String collection, Map<String, Object> param, String startTime,
                                                                 String endTime, Integer rows, Integer skip, Map<String, SolrQuery.ORDER> orderMap) throws Exception {

        SolrQuery solrQuery = new SolrQuery();
        StringBuffer query = new StringBuffer();
        if (StringUtils.isNotBlank(collection)) {
            query.append("(").append(" ns").append(":yiche.").append(collection).append(" OR ")
                    .append("ns").append(":").append(collection).append(")");
        }
        if (MapUtils.isEmpty(param)) {
            if (query.length() <= 0) {
                query.append("*:*");
            }
        } else {
            for (String key : param.keySet()) {
                if (key.equals("loc") || key.equals("distance")) {
                    continue;
                }
                if (query.length() > 0) {
                    query.append(" AND ");
                }
                if (key.equals("goodName")) {
                    query.append(" ( ").append("goodName").append(":").append(param.get(key)).append(" OR ")
                            .append("good_name_full").append(":").append("*" + param.get(key) + "*").append(" )");
                    continue;
                }

                if (key.equals("good_class_id")) {
                    String[] classIds = ((String) param.get("good_class_id")).split(",");
                    if (classIds.length > 1) {
                        int i = 0;
                        query.append(" ( ");
                        for (String classId : classIds) {
                            if (i > 0) {
                                query.append(" OR ");
                            }
                            query.append(key).append(":").append(classId);
                            i++;
                        }
                        query.append(" )");
                    } else {
                        query.append(key).append(":").append(classIds[0]);

                    }
                    continue;
                }
                query.append(key).append(":").append(param.get(key));

            }

        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        if (StringUtils.isNotEmpty(startTime)) {
            if (query.length() >= 0) {
                query.append(" AND ");
            }
            query.append("latm").append(":").append("[").append(sdf.format(DateUtils.StringToDate(startTime)));
            if (StringUtils.isNotEmpty(endTime)) {
                query.append(" TO ").append(sdf.format(DateUtils.StringToDate(startTime))).append("]");
            } else {
                query.append(" TO ").append(sdf.format(new Date())).append("]");

            }
        }

        if (rows == null) {
            rows = 10;
        } else if (rows > 20000) {
            LOGGER.warn("查询SOLR文档过长,被限制为20000条");
            rows = 20000;
        }
        if (skip == null) {
            skip = 0;
        }

        solrQuery.set("q", query.toString());
        solrQuery.set("rows", rows);
        solrQuery.set("start", skip);

        if (MapUtils.isNotEmpty(param)) {
            if (param.containsKey("loc")) {
                String loc = (String) param.get("loc");
                String fl = "*,distance:geodist(loc," + GeoUtils.parseLoc(loc) + ")";
                solrQuery.set("fl", fl);

                if (param.containsKey("distance")) {
                    solrQuery.set("fq", "{!geofilt}");
                    solrQuery.set("d", param.get("distance") + "");
                }

                solrQuery.set("sfield", "loc");
                solrQuery.set("pt", GeoUtils.parseLoc(loc));

            }


        }
        if (MapUtils.isNotEmpty(orderMap)) {
            for (String field : orderMap.keySet()) {
                if("priority".equals(field) || "latm".equals(field)){
                    //其他排序优先 时间和优先级别字段在最后
                    continue;
                }
                solrQuery.addSort(field, orderMap.get(field));
            }
        }

        //默认添加时间倒序排列
        solrQuery.addSort("latm", SolrQuery.ORDER.desc);
        solrQuery.addSort("priority", SolrQuery.ORDER.desc);

//        solrQuery.addSort("geodist()", SolrQuery.ORDER.desc);
        LOGGER.info("solr query condition:{}", URLDecoder.decode(solrQuery.toQueryString(), "UTF-8"));
//        solrQuery.set("sort","latm desc");
        QueryResponse response = solr.query(solrQuery);

        SolrDocumentList docs = response.getResults();

        LOGGER.info("hint num:{}", docs.getNumFound());

        return fastWrap2Map(docs);
    }

    /**
     * 不分页查询
     *
     * @param collection
     * @param query
     * @return
     * @throws Exception
     */
    public static List<Map<String, Object>> queryFromSolr(String collection, SolrQuery query) throws Exception {
        QueryResponse response = solr.query(query);
        SolrDocumentList docs = response.getResults();
        return fastWrap2Map(docs);
    }


    public static Object analysisQuery(String collection, String field, String value) throws Exception {
        SolrQuery query = new SolrQuery();
        query.add(CommonParams.QT, "/analysis/field");
        query.add(AnalysisParams.FIELD_VALUE, value);
        query.add(AnalysisParams.FIELD_NAME, field);
        query.add(AnalysisParams.FIELD_TYPE, "text_ik");

        QueryResponse response = solr.query(query);

        NamedList<Object> analysis = (NamedList<Object>) response.getResponse().get("analysis");

        NamedList<Object> fild_types = (NamedList<Object>) analysis.get("field_types");

        NamedList<Object> text_ik = (NamedList<Object>) fild_types.get("text_ik");

        NamedList<Object> index = (NamedList<Object>) text_ik.get("index");


        List<SimpleOrderedMap<String>> list = (ArrayList<SimpleOrderedMap<String>>) index.get("org.wltea.analyzer.lucene.IKTokenizer");// tokenizer node


        String nextQuery = "";
        for (Iterator<SimpleOrderedMap<String>> iter = list.iterator(); iter.hasNext(); ) {
            nextQuery += iter.next().get("text") + " ";

        }

        return nextQuery;
    }


    private static List<Map<String, Object>> fastWrap2Map(SolrDocumentList docs) {
        if (docs == null) {
            return null;
        }

        List<Map<String, Object>> result = new ArrayList<>();
        for (SolrDocument doc : docs) {
            Map<String, Object> item = new HashMap<>();
            for (String key : doc.getFieldNames()) {
                item.put(key, doc.getFieldValue(key));
            }
            result.add(item);
        }

        return result;
    }


}
